﻿using Athena.Http;
using BuddHa.Wechat.Mini.Responses;
using Microsoft.Extensions.Logging;
using System.Text.Encodings.Web;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Text;
using BuddHa.Wechat.Mini.Requests;
using BuddHa.Wechat.Mini.Cryptography;
using System.Security.Cryptography;

namespace BuddHa.Wechat.Mini.Dispatch
{
    public partial class WechatDispatch : IWechatDispatch
    {
        private readonly IHttpRequester _httpRequester;
        private ILogger _logger;

        public WechatDispatch(IHttpRequester httpRequester, ILogger<WechatDispatch> logger)
        {
            _httpRequester = httpRequester;
            _logger = logger;
        }

        /// <summary>
        /// 获取接口调用凭据
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="secret"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="Exception"></exception>
        public async Task<ResponseGetAccessToken> GetAccessToken(string appId, string secret)
        {
            if (string.IsNullOrWhiteSpace(appId))
            {
                throw new ArgumentNullException("AppId Is Null Or WriteSpace");
            }
            if (string.IsNullOrWhiteSpace(secret))
            {
                throw new ArgumentNullException("Secret Is Null Or WriteSpace");
            }

            var accessTokenResponse = await _httpRequester.GetAsync<ResponseGetAccessToken>(string.Format(ConstWechat.AccessTokenUri, appId, secret), ConstWechat.GetAccessToken);
            if (accessTokenResponse.ErrCode != null)
            {
                throw new Exception($"获取Access_Token失败，ErrorCode:{accessTokenResponse.ErrCode}, ErrorMessage:{accessTokenResponse.ErrMsg}");
            }
            return accessTokenResponse;
        }

        /// <summary>
        /// 获取不限制的小程序码
        /// </summary>
        /// <param name="accessToken"></param>
        /// <param name="sceneStr"></param>
        /// <param name="page"></param>
        /// <param name="envVersion"></param>
        /// <param name="checkPath"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public async Task<ResponseGetWxACode> GetWxACode(string accessToken, string sceneStr, string page, string envVersion, bool checkPath)
        {
            if (string.IsNullOrWhiteSpace(accessToken))
            {
                throw new ArgumentNullException("AccessToken Is Null Or WriteSpace");
            }

            var requestGetWxACode = new RequestGetWxACode()
            {
                Scene = sceneStr,
                Page = page,
                EnvVersion = envVersion,
                CheckPath = checkPath
            };
            var jsonSerializerOptions = new JsonSerializerOptions()
            {
                DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping

            };
            var athenaHttpConfiguration = _httpRequester.GetAthenaHttpClientOption("getWxQr");
            var responseWxACode = await _httpRequester.SendAsync(new Uri(string.Format(ConstWechat.GetWxACodeUri, accessToken)), Encoding.UTF8.GetBytes(JsonSerializer.Serialize(requestGetWxACode, jsonSerializerOptions)), HttpMethod.Post, athenaHttpConfiguration);
            var contentString = await responseWxACode.Content.ReadAsStringAsync();
            if (contentString.Contains("errcode"))
            {
                var responseGetWxACode = JsonSerializer.Deserialize<ResponseGetWxACode>(contentString);
                return responseGetWxACode;
            }
            var contentStream = await responseWxACode.Content.ReadAsStreamAsync();
            var response = new ResponseGetWxACode()
            {
                Buffer = contentStream,
            };
            return response;
        }

        /// <summary>
        /// 小程序登录,获取用户OpenId和SessionKey
        /// </summary>
        /// <param name="code"></param>
        /// <param name="appId"></param>
        /// <param name="appSecret"></param>
        /// <param name="grantType"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public async Task<ResponseWechatJscode2Session> WechatJscode2Session(string code, string appId, string appSecret, string grantType = "authorization_code")
        {
            string requestUri = string.Format(ConstWechat.WechatJscode2Session, appId, appSecret, code, grantType);
            var wechatOauthToken = await _httpRequester.GetAsync<ResponseWechatJscode2Session>(requestUri);
            if (string.IsNullOrWhiteSpace(wechatOauthToken.OpenId) || string.IsNullOrWhiteSpace(wechatOauthToken.SessionKey))
            {
                if (!string.IsNullOrWhiteSpace(wechatOauthToken.ErrMsg) || wechatOauthToken.ErrCode != 0)
                {
                    var errorMsg = $"wechatJscode2SessionError{wechatOauthToken.ErrMsg}|{wechatOauthToken.ErrCode}";
                    _logger.LogError(errorMsg);
                    throw new Exception($"微信授权登录_换取身份令牌失败，ErrorCode:{wechatOauthToken.ErrCode}, ErrorMessage:{wechatOauthToken.ErrMsg}");
                }
                else
                {
                    _logger.LogError("微信授权登录_微信返回信息缺失");
                    throw new Exception($"微信授权登录_微信返回信息缺失");
                }
            }
            return wechatOauthToken;
        }

        /// <summary>
        /// 获取用户个人信息
        /// </summary>
        public async Task<ResponseAuthInfo> GetUserEncryptKey(string encryptData, string accessToken, string openid, string sessionKey, string sigMethod = "hmac_sha256")
        {
            var signature = HmacSha256Util.CreateHash("", sessionKey);
            var requestUri = string.Format(ConstWechat.GetUserEncryptKey, accessToken, openid, signature, sigMethod);
            var userEncryptKey = await _httpRequester.GetAsync<ResponseGetUserEncryptKey>(requestUri);
            if (!string.IsNullOrWhiteSpace(userEncryptKey.ErrMsg) || userEncryptKey.ErrCode != 0)
            {
                var errorMsg = $"wechatJscode2SessionError{userEncryptKey.ErrMsg}|{userEncryptKey.ErrCode}";
                _logger.LogError(errorMsg);
                throw new Exception($"微信获取用户encryptKey失败，ErrorCode:{userEncryptKey.ErrCode}, ErrorMessage:{userEncryptKey.ErrMsg}");
            }
            if (userEncryptKey.KeyInfoLists.Count <= 0)
            {
                throw new Exception($"微信获取用户encryptKey失败，数据不存在");
            }
            var createTime = userEncryptKey.KeyInfoLists.Max(x => x.CreateTime);
            var keyInfoLists = userEncryptKey.KeyInfoLists.FirstOrDefault(x => x.CreateTime == createTime);
            return AuthInfo(keyInfoLists.EncryptKey, keyInfoLists.Iv, encryptData);

        }

        /// <summary>
        /// 获取用户个人信息
        /// </summary>
        /// <param name="sessionKey"></param>
        /// <param name="iv"></param>
        /// <param name="encrypteData"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public ResponseAuthInfo AuthInfo(string sessionKey, string iv, string encrypteData)
        {
            var aesUtil = new AESUtil(sessionKey.Replace(" ", "+"), iv.Replace(" ", "+"), PaddingMode.PKCS7, CipherMode.CBC);
            var decryptWechatData = aesUtil.Decrypt(encrypteData.Replace(" ", "+"));

            if (string.IsNullOrWhiteSpace(decryptWechatData))
            {
                throw new Exception($"微信小程序_解密用户信息失败");
            }
            var userInfoMini = JsonSerializer.Deserialize<ResponseAuthInfo>(decryptWechatData);

            if (userInfoMini == null)
            {
                throw new Exception($"微信小程序_解密用户信息失败");
            }

            return userInfoMini;
        }

        /// <summary>
        /// 获取用户手机号
        /// </summary>
        public async Task<ResponseGetUserPhoneNumber> GetUserPhoneNumber(string accessToken, string code)
        {
            var requestUri = string.Format(ConstWechat.GetUserPhoneNumber, accessToken, code);
            var userPhoneNumber = await _httpRequester.GetAsync<ResponseGetUserPhoneNumber>(requestUri);
            return userPhoneNumber;
        }

        /// <summary>
        /// 获取用户手机号
        /// </summary>
        /// <param name="sessionKey"></param>
        /// <param name="iv"></param>
        /// <param name="encrypteData"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public ResponseGetMoboilePhone GetWxMobilePhone(string sessionKey, string iv, string encrypteData)
        {
            var aesUtil = new AESUtil(sessionKey.Replace(" ", "+"), iv.Replace(" ", "+"), PaddingMode.PKCS7, CipherMode.CBC);
            var decryptWechatData = aesUtil.Decrypt(encrypteData.Replace(" ", "+"));
            if (string.IsNullOrWhiteSpace(decryptWechatData))
            {
                throw new Exception($"微信小程序_解密用户信息失败");
            }
            var wxMobilePhone = JsonSerializer.Deserialize<ResponseGetMoboilePhone>(decryptWechatData);

            if (wxMobilePhone == null)
            {
                throw new Exception($"微信小程序_解密用户信息失败");
            }

            return wxMobilePhone;
        }
    }
}
